package httpserver

import (
	"context"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

const (
	_defaultAddr            = ":8080"
	_defaultReadTimeout     = 5 * time.Second
	_defaultWriteTimeout    = 5 * time.Second
	_defaultShutdownTimeout = 3 * time.Second
)

// Server - Gin HTTP server wrapper
type Server struct {
	App             *gin.Engine
	server          *http.Server
	notify          chan error
	shutdownTimeout time.Duration
}

// New - creates a new Gin HTTP server with options
func New(opts ...Option) *Server {
	// Initialize Gin engine
	engine := gin.New()

	// Default middleware
	engine.Use(gin.Logger())
	engine.Use(gin.Recovery())

	// Create server instance
	s := &Server{
		App: engine,
		server: &http.Server{
			Addr:         _defaultAddr,
			Handler:      engine,
			ReadTimeout:  _defaultReadTimeout,
			WriteTimeout: _defaultWriteTimeout,
		},
		notify:          make(chan error, 1),
		shutdownTimeout: _defaultShutdownTimeout,
	}

	// Apply custom options
	for _, opt := range opts {
		opt(s)
	}

	return s
}

// Start - starts the HTTP server in a goroutine
func (s *Server) Start() {
	go func() {
		s.notify <- s.server.ListenAndServe()
		close(s.notify)
	}()
}

// Notify - returns a channel to receive server errors
func (s *Server) Notify() <-chan error {
	return s.notify
}

// Shutdown - gracefully shuts down the server
func (s *Server) Shutdown() error {
	ctx, cancel := context.WithTimeout(context.Background(), s.shutdownTimeout)
	defer cancel()
	return s.server.Shutdown(ctx)
}
